"""Test cases for Tool schema methods."""

from typing import Any

import pytest

from mini_agent.tools.base import Tool, ToolResult


class MockWeatherTool(Tool):
    """Mock weather tool for testing."""

    @property
    def name(self) -> str:
        return "get_weather"

    @property
    def description(self) -> str:
        return "Get weather information"

    @property
    def parameters(self) -> dict[str, Any]:
        return {
            "type": "object",
            "properties": {
                "location": {
                    "type": "string",
                    "description": "Location name",
                },
            },
            "required": ["location"],
        }

    async def execute(self, **kwargs) -> ToolResult:
        return ToolResult(success=True, content="Weather data")


class MockCalculatorTool(Tool):
    """Mock calculator tool for testing."""

    @property
    def name(self) -> str:
        return "calculator"

    @property
    def description(self) -> str:
        return "Perform calculations"

    @property
    def parameters(self) -> dict[str, Any]:
        return {
            "type": "object",
            "properties": {
                "expression": {
                    "type": "string",
                    "description": "Math expression",
                },
            },
            "required": ["expression"],
        }

    async def execute(self, **kwargs) -> ToolResult:
        return ToolResult(success=True, content="42")


class MockSearchTool(Tool):
    """Mock search tool with complex schema."""

    @property
    def name(self) -> str:
        return "search_database"

    @property
    def description(self) -> str:
        return "Search the database"

    @property
    def parameters(self) -> dict[str, Any]:
        return {
            "type": "object",
            "properties": {
                "query": {
                    "type": "string",
                    "description": "Search query",
                },
                "filters": {
                    "type": "object",
                    "properties": {
                        "category": {"type": "string"},
                        "min_price": {"type": "number"},
                        "max_price": {"type": "number"},
                    },
                },
                "limit": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 100,
                    "default": 10,
                },
            },
            "required": ["query"],
        }

    async def execute(self, **kwargs) -> ToolResult:
        return ToolResult(success=True, content="Search results")


class MockEnumTool(Tool):
    """Mock tool with enum parameter."""

    @property
    def name(self) -> str:
        return "set_status"

    @property
    def description(self) -> str:
        return "Set status"

    @property
    def parameters(self) -> dict[str, Any]:
        return {
            "type": "object",
            "properties": {
                "status": {
                    "type": "string",
                    "enum": ["active", "inactive", "pending"],
                    "description": "Status value",
                }
            },
            "required": ["status"],
        }

    async def execute(self, **kwargs) -> ToolResult:
        return ToolResult(success=True, content="Status set")


def test_tool_to_schema():
    """Test Tool.to_schema() method."""
    tool = MockWeatherTool()
    schema = tool.to_schema()

    assert isinstance(schema, dict)
    assert schema["name"] == "get_weather"
    assert schema["description"] == "Get weather information"
    assert "input_schema" in schema
    assert schema["input_schema"]["type"] == "object"
    assert "location" in schema["input_schema"]["properties"]
    assert schema["input_schema"]["required"] == ["location"]


def test_tool_to_openai_schema():
    """Test Tool.to_openai_schema() method."""
    tool = MockWeatherTool()
    schema = tool.to_openai_schema()

    assert isinstance(schema, dict)
    assert schema["type"] == "function"
    assert "function" in schema
    assert schema["function"]["name"] == "get_weather"
    assert schema["function"]["description"] == "Get weather information"
    assert "parameters" in schema["function"]
    assert schema["function"]["parameters"]["type"] == "object"
    assert "location" in schema["function"]["parameters"]["properties"]


def test_tool_schema_complex():
    """Test tool with complex input schema."""
    tool = MockSearchTool()
    schema = tool.to_schema()

    assert schema["name"] == "search_database"
    assert "query" in schema["input_schema"]["properties"]
    assert "filters" in schema["input_schema"]["properties"]
    assert "limit" in schema["input_schema"]["properties"]
    assert schema["input_schema"]["required"] == ["query"]


def test_tool_openai_schema_complex():
    """Test OpenAI schema conversion for complex tool."""
    tool = MockSearchTool()
    schema = tool.to_openai_schema()

    assert schema["type"] == "function"
    params = schema["function"]["parameters"]
    assert "query" in params["properties"]
    assert "filters" in params["properties"]
    assert "limit" in params["properties"]
    assert params["required"] == ["query"]


def test_multiple_tools():
    """Test creating multiple tool instances."""
    tool1 = MockWeatherTool()
    tool2 = MockCalculatorTool()

    tools = [tool1, tool2]
    assert len(tools) == 2
    assert tools[0].name == "get_weather"
    assert tools[1].name == "calculator"

    # Convert all to Anthropic schemas
    anthropic_schemas = [t.to_schema() for t in tools]
    assert len(anthropic_schemas) == 2
    assert all(isinstance(s, dict) for s in anthropic_schemas)
    assert all("name" in s and "description" in s and "input_schema" in s for s in anthropic_schemas)

    # Convert all to OpenAI schemas
    openai_schemas = [t.to_openai_schema() for t in tools]
    assert len(openai_schemas) == 2
    assert all(isinstance(s, dict) for s in openai_schemas)
    assert all(s["type"] == "function" for s in openai_schemas)


def test_tool_with_enum():
    """Test tool with enum parameter."""
    tool = MockEnumTool()
    schema = tool.to_schema()

    status_prop = schema["input_schema"]["properties"]["status"]
    assert "enum" in status_prop
    assert status_prop["enum"] == ["active", "inactive", "pending"]

    # Test OpenAI schema too
    openai_schema = tool.to_openai_schema()
    status_prop_openai = openai_schema["function"]["parameters"]["properties"]["status"]
    assert "enum" in status_prop_openai
    assert status_prop_openai["enum"] == ["active", "inactive", "pending"]


def test_tool_schema_consistency():
    """Test that both schema methods produce consistent data."""
    tool = MockCalculatorTool()

    anthropic_schema = tool.to_schema()
    openai_schema = tool.to_openai_schema()

    # Names should match
    assert anthropic_schema["name"] == openai_schema["function"]["name"]
    # Descriptions should match
    assert anthropic_schema["description"] == openai_schema["function"]["description"]
    # Parameters should match (just different nesting)
    assert anthropic_schema["input_schema"] == openai_schema["function"]["parameters"]


@pytest.mark.asyncio
async def test_tool_execute():
    """Test that tools can be executed."""
    tool = MockWeatherTool()
    result = await tool.execute(location="Tokyo")

    assert isinstance(result, ToolResult)
    assert result.success is True
    assert result.content == "Weather data"


if __name__ == "__main__":
    pytest.main([__file__, "-v"])
